#include "LogManager.h"

#include <ios>

#include <QCoreApplication>
#include <QDir>
#include <QString>
#include <QSharedPointer>

#include "spdlog/spdlog.h"
#include "spdlog/sinks/base_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"

class LogManager::Impl {

public:
	void InitSimLog(std::wstring file_name, int log_level)
	{
		QString qfile_name = QString::fromStdWString(file_name);
		std::string  file_name_local_string = qfile_name.toLocal8Bit().data();

		//auto max_size = 1024 * 1024 * 10;
		//auto max_files = 20;

		std::vector<spdlog::sink_ptr> sinks;
		sinks.push_back(std::make_shared<spdlog::sinks::daily_file_sink_mt>(file_name_local_string, 0, 0));
		m_logger = std::make_shared<spdlog::logger>("internal",std::begin(sinks),std::end(sinks));
		m_logger->set_level(static_cast<spdlog::level::level_enum>(log_level));
		m_logger->flush_on(spdlog::level::trace);
		spdlog::register_logger(m_logger);
		
		spdlog::set_pattern("[%Y-%m-%d %T.%e][thread %t][%l]%v");
	}

	void SetLevel(int level)
	{
		if (m_logger)
			m_logger->set_level(static_cast<spdlog::level::level_enum>(level));
	}

	void Dispose()
	{
		if (m_logger)
			spdlog::drop_all();
	}

public:
	std::shared_ptr<spdlog::logger> m_logger;

};


LogManager::LogManager() :
	m_impl(new Impl())
{
	QString appPath = QCoreApplication::applicationDirPath();
	QString logPath = appPath + QDir::separator() + "log" + QDir::separator() + "LOG.log";
	m_impl->InitSimLog(logPath.toStdWString(), LOG_LEVEL_TRACE);
}


LogManager::~LogManager()
{
	if (m_impl)
		m_impl->Dispose();
}

void LogManager::SetLevel(int level)
{
	if (m_impl)
		m_impl->SetLevel(level);
}

LogManager& LogManager::Instance()
{
	static LogManager log;
	return log;
}

void LogManager::Trace(const std::wstring& msg)
{
	if (msg.empty()) return;
	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->trace(qstr.toUtf8().data());
}

void LogManager::Debug(const std::wstring& msg)
{
	if (msg.empty()) return;

	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->debug(qstr.toUtf8().data());
}

void LogManager::Info(const std::wstring& msg)
{
	if (msg.empty()) return;
	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->info(qstr.toUtf8().data());
}

void LogManager::Warn(const std::wstring& msg)
{
	if (msg.empty()) return;
	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->warn(qstr.toUtf8().data());
}

void LogManager::Error(const std::wstring& msg)
{
	if (msg.empty()) return;
	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->error(qstr.toUtf8().data());
}

void LogManager::Critical(const std::wstring& msg)
{
	if (msg.empty()) return;
	QString qstr = QString::fromStdWString(msg);
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->critical(qstr.toUtf8().data());
}

void LogManager::Trace(const std::string& msg)
{
	if (msg.empty()) return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->trace(msg);
}

void LogManager::Debug(const std::string& msg)
{
	if (msg.empty()) 
		return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->debug(msg);
}

void LogManager::Info(const std::string& msg)
{
	if (msg.empty()) return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->info(msg);
}

void LogManager::Warn(const std::string& msg)
{
	if (msg.empty()) return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->warn(msg);
}

void LogManager::Error(const std::string& msg)
{
	if (msg.empty()) return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->error(msg);
}

void LogManager::Critical(const std::string& msg)
{
	if (msg.empty()) return;
	if (m_impl && m_impl->m_logger)
		m_impl->m_logger->critical(msg);
}
